
import { _decorator, Component, Node, Vec2, Vec3, EventTouch, UIOpacity } from 'cc';
const { ccclass, property } = _decorator;

let _tempVec2 = new Vec2;
let _tempVec3 = new Vec3;
/**
 * 虚拟摇杆按键
 */
export class JoystickKey {
    public press: boolean = false;  // 是否触摸
    public direction: Vec3 = new Vec3;      // 遥感方向
    public rotation: number = 0;            // 遥感角度
    public magnitude: number = 0;           // 遥感距离中心比例

    reset () {
        this.press = false;
        this.direction.x = 0;
        this.direction.y = 0;
        this.rotation = 0;
        this.magnitude = 0;
    }
}

/**
 * 虚拟摇杆
 */

@ccclass('Joystick')
export class Joystick extends Component {
    @property({ tooltip: "触摸面板是否可以移动" })
    enableMovePanel: boolean = false; // 触摸面板是否可以移动
    @property(Node)
    touchNode: Node | null = null;
    @property(Node)
    bgPanel: Node | null = null;
    @property(Node)
    maskPanel: Node | null = null;

    @property
    maxRadius: number = 100;                // 最大触摸位移半径

    public joystickKey: JoystickKey = new JoystickKey();
    private _touchStartPosition: Vec3 = new Vec3;   // 触摸点本地坐标
    private _touchStartWorldPosition: Vec3 = new Vec3;  // 触摸点世界坐标
    private _bindMovement: Vec2 | null = null;

    start () {
        this.touchNode?.getPosition(this._touchStartPosition);
    }

    bindInput (movement: Vec2 | null) {
        this._bindMovement = movement;
    }

    // 注册触摸事件
    onEnable () {
        if (this.enableMovePanel && this.maskPanel) {
            this.maskPanel.on(Node.EventType.TOUCH_START, this._touchMaskBegin, this);
            this.maskPanel.on(Node.EventType.TOUCH_MOVE, this._touchMaskMove, this);
            this.maskPanel.on(Node.EventType.TOUCH_END, this._touchMaskEnd, this);
            this.maskPanel.on(Node.EventType.TOUCH_CANCEL, this._touchMaskEnd, this);
        } else if (this.bgPanel) {
            this.bgPanel.on(Node.EventType.TOUCH_START, this._touchPanelBegin, this);
            this.bgPanel.on(Node.EventType.TOUCH_MOVE, this._touchPanelMove, this);
            this.bgPanel.on(Node.EventType.TOUCH_END, this._touchPanelEnd, this);
            this.bgPanel.on(Node.EventType.TOUCH_CANCEL, this._touchPanelEnd, this);
        }
    }

    // 取消注册触摸事件
    onDisable () {
        if (this.enableMovePanel && this.maskPanel) {
            this.maskPanel.off(Node.EventType.TOUCH_START, this._touchMaskBegin, this);
            this.maskPanel.off(Node.EventType.TOUCH_MOVE, this._touchMaskMove, this);
            this.maskPanel.off(Node.EventType.TOUCH_END, this._touchMaskEnd, this);
            this.maskPanel.off(Node.EventType.TOUCH_CANCEL, this._touchMaskEnd, this);
        } else if (this.bgPanel) {
            this.bgPanel.off(Node.EventType.TOUCH_START, this._touchPanelBegin, this);
            this.bgPanel.off(Node.EventType.TOUCH_MOVE, this._touchPanelMove, this);
            this.bgPanel.off(Node.EventType.TOUCH_END, this._touchPanelEnd, this);
            this.bgPanel.off(Node.EventType.TOUCH_CANCEL, this._touchPanelEnd, this);
        }
    }

    /**
     * 面板触摸开始
     * @param event 
     */
    private _touchPanelBegin (event: EventTouch) {
        this.joystickKey.press = true;

        // 第一次需要计算世界坐标获取触点位置，后续只要用本地坐标即可
        event.getUILocation(_tempVec2);
        this.touchNode?.getWorldPosition(this._touchStartWorldPosition);
        this._convertJoystickPosition(_tempVec2);
    }

    /**
     * 面板触摸移动
     * @param event 
     */
    private _touchPanelMove (event: EventTouch) {
        event.getUILocation(_tempVec2);
        this._convertJoystickPosition(_tempVec2);
    }

    /**
     * 应用到摇杆节点坐标
     * @param touchPosition 
     */
    private _convertJoystickPosition (touchPosition: Vec2) {
        // 计算出触摸点点实际偏差值
        Vec3.subtract(_tempVec3, this._touchStartWorldPosition, this._touchStartPosition);
        Vec3.set(this.joystickKey.direction, touchPosition.x - _tempVec3.x, touchPosition.y - _tempVec3.y, 0);
        this._bindMovement?.set(this.joystickKey.direction.x, this.joystickKey.direction.y);
        let distance = Vec3.distance(this.joystickKey.direction, Vec3.ZERO);
        if (distance >= this.maxRadius) {
            distance = this.maxRadius;
        }
        this.joystickKey.direction.normalize();
        this.joystickKey.magnitude = distance / this.maxRadius;

        // 计算方向
        this.joystickKey.rotation = -Math.atan2(this.joystickKey.direction.x, this.joystickKey.direction.y) * (180.0 / Math.PI);
        Vec3.multiplyScalar(_tempVec3, this.joystickKey.direction, distance);

        // 计算偏差值，并矫正触摸点
        Vec3.add(_tempVec3, _tempVec3, this._touchStartPosition);
        this.touchNode?.setPosition(_tempVec3);
    }

    /**
     * 面板触摸结束
     * @param event 
     */
    private _touchPanelEnd (event: EventTouch) {
        this.touchNode?.setPosition(this._touchStartPosition);
        this.joystickKey.reset();
        this._bindMovement?.set(0, 0);
    }

    /**
     * 蒙版触摸开始
     * @param event 
     */
    private _touchMaskBegin (event: EventTouch) {
        // 将bgNode位移到当前触摸点
        event.getUILocation(_tempVec2);

        Vec3.set(_tempVec3, _tempVec2.x, _tempVec2.y, 0)

        if (this.bgPanel) {
            this.bgPanel.setWorldPosition(_tempVec3);
            let uiOpacity = this.bgPanel.getComponent(UIOpacity);
            if (!uiOpacity) {
                uiOpacity = this.bgPanel.addComponent(UIOpacity);
            }
            uiOpacity.opacity = 255; // 
        }

        // 获取当前触摸点点世界坐标
        this.touchNode?.getWorldPosition(this._touchStartWorldPosition);

        this.joystickKey.press = true;
    }

    /**
     * 蒙版触摸移动
     * @param event 
     */
    private _touchMaskMove (event: EventTouch) {
        event.getUILocation(_tempVec2);
        this._convertJoystickPosition(_tempVec2);
    }

    /**
     * 蒙版触摸结束
     * @param event 
     */
    private _touchMaskEnd (event: EventTouch) {
        if (this.bgPanel) {
            this.bgPanel.getComponent(UIOpacity)!.opacity = 0;
        }

        this.touchNode?.setPosition(this._touchStartPosition);
        this.joystickKey.reset();
        this._bindMovement?.set(0, 0);
    }
}